package com.java.common.pay.wxpay.controller;

import com.java.common.pay.wxpay.conf.WxConfig;
import com.java.common.pay.wxpay.utils.HTTPTool;
import com.java.common.pay.wxpay.utils.MD5Tool;
import com.java.common.pay.wxpay.utils.SignTool;
import com.java.common.pay.wxpay.utils.XMLTool;
import com.java.common.utils.tool.StringUtils;
import com.java.framework.web.controller.BaseController;
import com.java.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.dom4j.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.*;

@Api("微信支付")
@RestController
@RequestMapping("/test/user")
public class WxPayController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(WxPayController.class);

    @ApiOperation("生成微信支付扫一扫的二维码url")
    @PostMapping(value = "/makeTenpayScanUrl")
    public AjaxResult makeTenpayScanUrl(HttpServletRequest request,
                                                        @ApiParam("订单id，必传") @RequestParam(value = "orderId", required = false) String orderId) {
        try {
            Long time_stamp = new Date().getTime() / 1000;
            SortedMap<String, Object> signMap = new TreeMap<String, Object>();
            signMap.put("appid", WxConfig.weixin_appid_scan);
            signMap.put("mch_id", WxConfig.weixin_mch_id_scan);
            signMap.put("nonce_str", MD5Tool.encryptString(String.valueOf(time_stamp)));
            signMap.put("time_stamp", new Date().getTime() / 1000);
            signMap.put("product_id", "orderid");    // 订单id，扫描回调的时候微信会返回这个product_id
            signMap.put("sign", SignTool.signScan(signMap));
            String wm = "weixin://wxpay/bizpayurl?appid=" + signMap.get("appid") + "&mch_id=" + signMap.get("mch_id") + "&nonce_str=" + signMap.get("nonce_str") + "&product_id=" + signMap.get("product_id") + "&time_stamp=" + signMap.get("time_stamp") + "&sign=" + signMap.get("sign");
            Map<String, String> map = new HashMap<String, String>();
            map.put("wm", wm);
            return AjaxResult.success(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error(null);
    }

    /**
     * 方法名：tenpayScan
     * 详述：微信用户扫了二维码以后的回调统一下单接口
     *
     * @param request
     * @param response
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/tenpayScan")
    public String tenpayScan(HttpServletRequest request, HttpServletResponse response) {
        try {
            log.info("----------- tenpayScan() : come !");
            Long time_stamp = new Date().getTime() / 1000;
            // 获取微信回调参数
            Map<String, String> reqMap = XMLTool.XMLToMap(request);
            if (reqMap != null) {
                //Tool.printMap(reqMap);
                String product_id = reqMap.get("product_id");    // 生成微信扫描二维码时传入的，通常给这个参数放订单id
                if (StringUtils.isNotEmpty(product_id)) {
                    // 用 product_id 查询订单去查订单，把查出来的订单里面的订单号放进下面的out_trade_no
                    /*
                     * 统一下单接口需要的参数
                     */
                    String ip = request.getRemoteAddr();
                    SortedMap<String, Object> map = new TreeMap<String, Object>();
                    map.put("appid", WxConfig.weixin_appid_scan);
                    map.put("mch_id", WxConfig.weixin_mch_id_scan);
                    map.put("nonce_str", MD5Tool.encryptString(String.valueOf(time_stamp)));
                    map.put("body", "时间出租");
                    map.put("out_trade_no", System.currentTimeMillis() + "");        //订单号
                    map.put("total_fee", 1);
                    map.put("spbill_create_ip", ip);
                    map.put("notify_url", WxConfig.notify_url_scan);
                    map.put("trade_type", "NATIVE");
                    map.put("product_id", product_id);
                    map.put("sign", SignTool.signScan(map));
                    /*
                     * 把参数转成xml格式
                     */
                    String xml = XMLTool.mapToXML(map);
                    /*
                     * 请求微信统一下单url
                     */
                    String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
                    String responseStr = HTTPTool.post(xml, url);
                    log.info("--------------- tenpayScan() : 统一下单返回结果：\n" + responseStr);
                    Document doc = XMLTool.strToXMLDocment(responseStr);
                    String return_code = doc.getRootElement().elementText("return_code");
                    String return_msg = doc.getRootElement().elementText("return_msg");
                    String prepay_id = null;
                    if (StringUtils.isNotEmpty(return_code) && return_code.equals("SUCCESS")) {
                        String result_code = doc.getRootElement().elementText("result_code");
                        if (StringUtils.isNotEmpty(result_code) && result_code.equals("SUCCESS")) {
                            prepay_id = doc.getRootElement().elementText("prepay_id");
                            log.info("-------- tenpayScan() : 获取到的预支付id prepay_id 是：" + prepay_id);
                            /*
                             * 把相关参数按要求转成xml响应给微信服务器，微信服务器向客户端发起输入支付密码
                             */
                            SortedMap<String, Object> signParams = new TreeMap<String, Object>();
                            signParams.put("return_code", return_code);
                            signParams.put("return_msg", return_msg);
                            signParams.put("appid", WxConfig.weixin_appid_scan);
                            signParams.put("mch_id", WxConfig.weixin_mch_id_scan);
                            signParams.put("nonce_str", MD5Tool.encryptString(String.valueOf(time_stamp)));
                            signParams.put("prepay_id", prepay_id);
                            signParams.put("result_code", return_code);
                            signParams.put("err_code_des", return_msg);
                            signParams.put("sign", SignTool.signScan(signParams));

                            response.setHeader("ContentType", "text/xml");
                            response.setHeader("Pragma", "No-cache");
                            response.setHeader("Cache-Control", "no-cache");
                            response.setDateHeader("Expires", 0);
                            PrintWriter out = response.getWriter();
                            out.flush();
                            String returnStr = XMLTool.mapToXML(signParams);
                            log.info("---------- return : \n" + returnStr);
                            out.print(returnStr);
                            out.close();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 方法名：tenpayNotifyScan
     * 详述：微信扫码支付结果异步通知接口
     *
     * @param request
     * @param response
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/tenpayNotifyScan")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public synchronized String tenpayNotifyScan(HttpServletRequest request, HttpServletResponse response) {
        log.info("------- tenpayNotifyScan() : come !");
        try {
            Map<String, String> map = XMLTool.XMLToMap(request);
            //Tool.printMap(map);
            String return_code = map.get("return_code");
            log.info("------- tenpayNotifyScan() return_code : " + return_code);
            if (StringUtils.isNotEmpty(return_code) && return_code.equals("SUCCESS")) {
                String result_code = map.get("result_code");
                log.info("------- tenpayNotifyScan() result_code : " + result_code);
                if (StringUtils.isNotEmpty(result_code) && result_code.equals("SUCCESS")) {
                    String out_trade_no = map.get("out_trade_no");        // 订单号
                    String transaction_id = map.get("transaction_id");    // 微信交易号（交易id，也叫流水id、微信的订单id）
                    log.info("------- tenpayNotifyScan() : 支付成功！\n out_trade_no : " + out_trade_no + ", transaction_id : " + transaction_id);

                }
            }
            response.setHeader("ContentType", "text/xml");
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            PrintWriter out = response.getWriter();
            out.flush();
            out.print(return_code);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @ApiOperation("微信公众号发起支付")
    @PostMapping(value = "/tenpayPub")
    public AjaxResult tenpayJSAPI(HttpServletRequest request, HttpServletResponse response,
                                                  @ApiParam("微信openId") @RequestParam(value = "openId", required = true) String openId) {
        try {
            log.info("----------- tenpayJSAPI() : come !");
            Long time_stamp = new Date().getTime() / 1000;
            // 统一下单接口需要的参数
            String ip = request.getRemoteAddr();
            SortedMap<String, Object> sp = new TreeMap<String, Object>();
            sp.put("appid", WxConfig.weixin_appid_pub);
            sp.put("mch_id", WxConfig.weixin_mch_id_pub);
            sp.put("nonce_str", MD5Tool.encryptString(String.valueOf(time_stamp)));
            sp.put("body", "产品名称");
            sp.put("out_trade_no", "订单号");
            sp.put("total_fee", 1);
            sp.put("spbill_create_ip", ip);
            sp.put("notify_url", WxConfig.notify_url_pub);
            sp.put("trade_type", "JSAPI");
            sp.put("openid", openId);
            sp.put("sign", SignTool.signPub(sp));
            /*
             * 把参数转成xml格式
             */
            String xml = XMLTool.mapToXML(sp);
            /*
             * 请求微信统一下单url
             */
            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String responseStr = HTTPTool.post(xml, url);
            log.info("--------------- tenpayJSAPI() : 统一下单返回结果：\n" + responseStr);
            Document doc = XMLTool.strToXMLDocment(responseStr);
            String return_code = doc.getRootElement().elementText("return_code");
            String return_msg = doc.getRootElement().elementText("return_msg");
            String prepay_id = null;
            if (StringUtils.isNotEmpty(return_code) && return_code.equals("SUCCESS")) {
                String result_code = doc.getRootElement().elementText("result_code");
                if (StringUtils.isNotEmpty(result_code) && result_code.equals("SUCCESS")) {
                    prepay_id = doc.getRootElement().elementText("prepay_id");
                    log.info("-------- tenpayJSAPI() : 获取到的预支付id prepay_id 是：" + prepay_id);
                    SortedMap<String, Object> map = new TreeMap<String, Object>();
                    map.put("appId", WxConfig.weixin_appid_pub);
                    map.put("timeStamp", System.currentTimeMillis() / 1000 + "");
                    map.put("nonceStr", UUID.randomUUID().toString().replace("-", "").substring(10));
                    map.put("package", "prepay_id=" + prepay_id);
                    map.put("signType", "MD5");
                    map.put("paySign", SignTool.signPub(map).toUpperCase());
                    map.put("prepay_id", prepay_id);
                    return AjaxResult.success(map);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error(null);
    }


    /**
     * 方法名：tenpayNotifyPub
     * 详述：微信公众号支付结果异步通知接口
     *
     * @param request
     * @param response
     * @return
     */
    @ApiIgnore
    @RequestMapping(value = "/tenpayNotifyPub")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public synchronized String tenpayNotifyPub(HttpServletRequest request, HttpServletResponse response) {
        log.info("------- tenpayNotifyPub() : come !");
        try {
            Map<String, String> map = XMLTool.XMLToMap(request);
            //Tool.printMap(map);
            String return_code = map.get("return_code");
            log.info("------- tenpayNotifyPub() return_code : " + return_code);
            if (StringUtils.isNotEmpty(return_code) && return_code.equals("SUCCESS")) {
                String result_code = map.get("result_code");
                log.info("------- tenpayNotifyPub() result_code : " + result_code);
                if (StringUtils.isNotEmpty(result_code) && result_code.equals("SUCCESS")) {
                    String out_trade_no = map.get("out_trade_no");        // 订单号
                    String transaction_id = map.get("transaction_id");    // 微信交易号（交易id，也叫流水id、微信的订单id）
                    log.info("------- tenpayNotifyPub() : 支付成功！\n out_trade_no : " + out_trade_no + ", transaction_id : " + transaction_id);
                }
            }
            response.setHeader("ContentType", "text/xml");
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            PrintWriter out = response.getWriter();
            out.flush();
            out.print(return_code);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
